﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GameCamera
{
  public class Camera
  {
    private float yaw, pitch, roll, speed;
    private Vector3 position, target;
    public Matrix viewMatrix, projectionMatrix, cameraRotation;
    private bool WASDCamera;
    public Viewport viewport;
    private float aspectRatio;
    private BoundingFrustum cameraFrustum;

    public BoundingFrustum CameraFrustum
    {
      get { return cameraFrustum; }
    }

    public Vector3 Position
    {
      get { return position; }
    }

    public Camera(bool WASDCamera, Vector3 position, Viewport viewport)
    {
      this.WASDCamera = WASDCamera;
      this.viewport = viewport;
      this.cameraFrustum = new BoundingFrustum(Matrix.Identity);
      yaw = pitch = roll = 0.0f;
      speed = 0.3f;
      this.position = position;
      target = new Vector3();
      viewMatrix = Matrix.Identity;
      aspectRatio = (float)viewport.Width / (float)viewport.Height;
      projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(60.0f), aspectRatio, 0.5f, 1000.0f);
      cameraRotation = Matrix.Identity;
    }

    private void HandleInput()
    {
      KeyboardState keyboardState = Keyboard.GetState();
      Vector3 moveVector = Vector3.Zero;
      if (keyboardState.IsKeyDown(Keys.W))
      {
        moveVector += new Vector3(0, 0, -1);
      }
      if (keyboardState.IsKeyDown(Keys.S))
      {
        moveVector += new Vector3(0, 0, 1);
      }
      if (keyboardState.IsKeyDown(Keys.A))
      {
        moveVector += new Vector3(-1, 0, 0);
      }
      if (keyboardState.IsKeyDown(Keys.D))
      {
        moveVector += new Vector3(1, 0, 0);
      }
      if (keyboardState.IsKeyDown(Keys.E))
      {
        moveVector += new Vector3(0, 1, 0);
      }
      if (keyboardState.IsKeyDown(Keys.Q))
      {
        moveVector += new Vector3(0, -1, 0);
      }
      if (keyboardState.IsKeyDown(Keys.Up))
      {
        pitch += .02f;
      }
      if (keyboardState.IsKeyDown(Keys.Down))
      {
        pitch -= .02f;
      }
      if (keyboardState.IsKeyDown(Keys.Left))
      {
        yaw += .02f;
      }
      if (keyboardState.IsKeyDown(Keys.Right))
      {
        yaw -= .02f;
      }
      MoveCamera(moveVector);
    }

    private void MoveCamera(Vector3 vectorToAdd)
    {
      Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);
      Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
      position += speed * rotatedVector;
    }

    public void Update()
    {
      HandleInput();
      UpdateViewMatrix();
    }

    public void UpdateViewMatrix()
    {
      Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);

      Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
      Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
      Vector3 cameraFinalTarget = this.position + cameraRotatedTarget;

      target = cameraFinalTarget;

      Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
      Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);

      viewMatrix = Matrix.CreateLookAt(this.position, cameraFinalTarget, cameraRotatedUpVector);


      viewMatrix = Matrix.CreateLookAt(position, target, cameraRotation.Up);
      viewMatrix = Matrix.CreateLookAt(position, target, Vector3.Up);

      cameraFrustum.Matrix = viewMatrix * projectionMatrix;
    }
  }
}
